LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_signed.all;
USE work.components.all;

ENTITY fetch IS
PORT (  Tick				: IN	STD_LOGIC_VECTOR(2 DOWNTO 0);
		Clock				: IN	STD_LOGIC;
		Instr, Immed		: OUT	STD_LOGIC_VECTOR(7 DOWNTO 0));
END fetch;

ARCHITECTURE behavior OF fetch IS
	--fios  do fetch
	SIGNAL PCin, RAin						: STD_LOGIC;
	SIGNAL RAOut, ImmedOut				 	: STD_LOGIC; --escolha do proximo endereco (jumps, jals e jrs)
	SIGNAL NextOut, PosImmOut        	   	: STD_LOGIC; --escolha do proximo endereco (pular imediato ou nao)
	SIGNAL PC, RA 							: STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL nextAddress, immedAdd, posImmed 	: STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL instruction, immediate	 	   	: STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL nextAddressWire     				: STD_LOGIC_VECTOR(7 DOWNTO 0);
	
BEGIN
	--PC
	regPC: regn	PORT MAP (nextAddressWire, PCin, Clock, PC);
	regRA: regn PORT MAP (posImmed, RAin, Clock, RA);

	--instruction_memory
	instMem: 	inst_mem PORT MAP (PC, instruction, immediate);	--carrega instrucao e imediato

	--instruction adder
	memAdder: 		adder PORT MAP (PC, nextAddress); 		--endereco da proxima instrucao
	posImmedAdder: 	adder PORT MAP (nextAddress, posImmed); --endereco pos-imediato
	
	--tri-state buffers (selecionam o proximo endereco a ir pro PC)
	triNext: trin PORT MAP (nextAddress, NextOut, nextAddressWire);
	triPosI: trin PORT MAP (posImmed, PosImmOut, nextAddressWire);
	triImmd: trin PORT MAP (immediate, ImmedOut, nextAddressWire);
	triRA  : trin PORT MAP (RA, RAOut, nextAddressWire);
	
	Instr <= instruction;
	WITH instruction(7) SELECT
		Immed 	<= 	immediate WHEN '1',
					"00000000" WHEN OTHERS;
	
	 Converte : PROCESS (Tick, instruction)
	 BEGIN
		PosImmOut <= '0'; 
		NextOut <= '0';
		PCin <= '0';
		CASE Tick IS
		   WHEN "000" =>
				RAin <= '0';
				PCin <= '0';
				PosImmOut <= '0';
				ImmedOut <= '0';
				NextOut <= '0';
				RAOut <= '0';
		   WHEN "001" =>
				CASE instruction(7 DOWNTO 4) IS
						WHEN "1111" => --jal
							--pc <- end
							RAin <= '1';
						WHEN OTHERS =>
							RAin <= '0';
					END CASE;
		   WHEN "010" => 
				IF Clock = '1' THEN
					PCin <= '1';
				END IF;
				IF instruction(7) = '1' THEN
					CASE instruction(7 DOWNTO 4) IS
						WHEN "1110" => --jump
							-- pc <- end
							ImmedOut <= '1';
						WHEN "1111" => --jal
							--pc <- end
							ImmedOut <= '1';
						WHEN OTHERS =>
							PosImmOut <= '1';
							NextOut <= '0';
					END CASE;
				ELSIF instruction(7) = '0' THEN
					CASE instruction(7 DOWNTO 4) IS
						WHEN "0111" => --jr
							-- pc <- ra
							RAOut <= '1';
						WHEN OTHERS =>
							PosImmOut <= '0';
							NextOut <= '1';
					END CASE;
				END IF;
			WHEN OTHERS =>
		END CASE;
	END PROCESS Converte;
	

END behavior;